Skip to content

ci(sdk): replace release-plz with tag-driven publish#692

Merged
kvinwang merged 4 commits into
masterfrom
ci/sdk-tag-driven-release
May 19, 2026
Merged

ci(sdk): replace release-plz with tag-driven publish#692
kvinwang merged 4 commits into
masterfrom
ci/sdk-tag-driven-release

Conversation

@kvinwang
Copy link
Copy Markdown
Collaborator

Summary

Walks back the release-plz setup (#691) in favor of a simple tag-driven workflow. release-plz turned out to be the wrong tool for this repo because:

  1. Org-level policy blocks it. Dstack-TEE disallows GitHub Actions from creating pull requests, which is the central mechanism release-plz uses. The Release PR creation step returns HTTP 403 and there's no clean workaround that doesn't require a PAT or custom GitHub App.
  2. Overkill for this cadence. The SDK has 2 coupled crates that share a version and ship infrequently. PR-driven automation with auto-bump and changelog scanning is solving a problem we don't have.

This switches to an idempotent, validated tag-driven publish that fixes every concrete failure mode from the old workflow.

What changes

  • New .github/workflows/rust-sdk-release.yml (replaces the previous content):

    • Triggers on dstack-sdk-v* tags only (single tag for both crates — they share a version).
    • Validates that the tag version matches all three sources before publishing:
      • sdk/rust/types/Cargo.toml [package.version]
      • sdk/rust/Cargo.toml [package.version]
      • root Cargo.toml [workspace.dependencies.dstack-sdk-types.version]
      • Fails fast with a clear message if any drift — directly fixes the rust-sdk-v0.5.9 vs 0.1.2 failure mode that broke the previous publishes.
    • Publishes via .github/scripts/cargo-publish-idempotent.sh: cargo publish is wrapped so "already exists on crates.io" is treated as success. A partial-failure mid-release can be retried by pushing the same tag, without getting stuck on the first crate.
    • Auto-creates a matching GitHub Release.
    • Same environment: sdk-release + OIDC trusted publishing as before, so existing crates.io trusted publisher config keeps working.
  • New .github/scripts/cargo-publish-idempotent.sh — the wrapper described above.

  • Removed release-plz.toml.

How to release (human-facing)

# Bump versions (cargo-edit's set-version; cargo install cargo-edit if missing)
cargo set-version -p dstack-sdk-types -p dstack-sdk 0.1.3

# Also bump the workspace dependency pin in root Cargo.toml
#   dstack-sdk-types = { path = "sdk/rust/types", version = "0.1.3", ... }

git commit -am "release: dstack-sdk 0.1.3"
git tag dstack-sdk-v0.1.3
git push origin master dstack-sdk-v0.1.3

If you forget to bump one of the three version sources, the workflow fails with a checklist showing which one is wrong, before touching crates.io.

Existing drift uncovered

The current Cargo.toml workspace dep pin is 0.1.1 while both crates are at 0.1.2. The validator catches this — the next release tag must include a fixed workspace dep pin.

Test plan

  • CI green on the PR
  • After merge: bump versions to 0.1.3 (including the workspace dep pin fix), tag dstack-sdk-v0.1.3, push, verify both crates publish to crates.io
  • Verify idempotency by pushing the same tag again (delete + re-tag) — workflow should succeed without errors

The release-plz setup hit a wall: the Dstack-TEE org disallows GitHub
Actions from creating pull requests, which is the central mechanism
release-plz relies on. Plus, the SDK release cadence is low and only
involves two coupled crates, so PR-driven automation is overkill.

Replace with a simple, explicit workflow:

- Trigger: push of a tag matching `dstack-sdk-v*` (single tag covers
  both crates, which share a version).
- Validate that all three version sources agree with the tag:
    - sdk/rust/types/Cargo.toml [package.version]
    - sdk/rust/Cargo.toml [package.version]
    - root Cargo.toml [workspace.dependencies.dstack-sdk-types.version]
  Fail fast with a clear message if they drift — avoiding the
  "tag rust-sdk-v0.5.9 but crate is 0.1.2" failure mode that broke
  the previous workflow.
- Publish idempotently via .github/scripts/cargo-publish-idempotent.sh:
  "already exists on crates.io" is treated as success, so a partial
  failure can be retried by pushing the same tag without getting stuck
  on the first crate.
- Auto-create a matching GitHub Release for visibility.

Drop release-plz.toml.

Release workflow for humans:
    cargo set-version -p dstack-sdk-types -p dstack-sdk <version>
    # also bump root Cargo.toml workspace.dependencies.dstack-sdk-types.version
    git commit -am "release: dstack-sdk <version>"
    git tag dstack-sdk-v<version>
    git push origin master "dstack-sdk-v<version>"
Copilot AI review requested due to automatic review settings May 19, 2026 11:45
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR replaces the release-plz-based SDK release flow with a tag-driven crates.io publishing workflow for the Rust SDK crates.

Changes:

  • Removes release-plz.toml.
  • Reworks .github/workflows/rust-sdk-release.yml to publish on dstack-sdk-v* tags after validating crate/workspace versions.
  • Adds an idempotent cargo publish wrapper for already-published crates.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

File Description
release-plz.toml Removes release-plz configuration.
.github/workflows/rust-sdk-release.yml Defines tag-triggered validation, publishing, and GitHub Release creation.
.github/scripts/cargo-publish-idempotent.sh Wraps cargo publish to treat already-published crate versions as success.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread .github/workflows/rust-sdk-release.yml Outdated
Comment on lines +92 to +95
gh release create "$GITHUB_REF_NAME" \
--title "dstack-sdk $VERSION" \
--notes "Published to crates.io: [dstack-sdk@$VERSION](https://crates.io/crates/dstack-sdk/$VERSION), [dstack-sdk-types@$VERSION](https://crates.io/crates/dstack-sdk-types/$VERSION)" \
--verify-tag
The workspace dependency pin for dstack-sdk-types was at 0.1.1 while
both crates have been at 0.1.2 since release. This pin had no effect on
the path-based dependency resolution but blocked crates.io publishing
(cargo refuses if the version in workspace.dependencies doesn't exist).
Address Copilot review: previously a successful run would create the
GitHub Release, and any retry (push the same tag again) would then
fail at this step even though the cargo publish wrapper handles
"already exists". Skip the create when a release for this tag is
already there, matching the cargo publish wrapper's behavior.
@kvinwang kvinwang merged commit 2deeab7 into master May 19, 2026
16 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants